////////////////////////////////////////////////////////////////////////////// 
//
//  jtag_shdw_reg.v
//
//
//  通用寄存器，可通过JTAG TAP控制器读取或写入。
//  它包含一个影子寄存器，因此q输出将始终是“官方”jtag版本
//
//  Original Author: 
//  Current Owner:   
//
////////////////////////////////////////////////////////////////////////////// 
//
// Copyright (C) 2011 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
////////////////////////////////////////////////////////////////////////////// 
//
//    Perforce Information
//    $Author: 
//    $File: rtl/jtag_shdw_reg.v $
//    $DateTime: 
//    $Revision: 
//
////////////////////////////////////////////////////////////////////////////// 

`timescale 1ns/10fs
module np_jtag_shdw_reg #(parameter WIDTH=2,
                       parameter [WIDTH-1:0] RST_VAL = 0,
                       parameter [WIDTH-1:0] SHDW_EN = {WIDTH{1'b1}} // 默认情况下SHDW Register启用
                       ) (
output wire [WIDTH-1:0] q,
output wire             serial_out,
input  wire             rst,
input  wire             clk,
input  wire             clk_n,
input  wire             capture,
input  wire             update,
input  wire             shift,
input  wire             select,
input  wire [WIDTH-1:0] capture_val,
input  wire             serial_in
);
    

// 影子寄存器寄存器在计时但不移位时捕获并行的capture_val数据。
// 当移位时，最低有效位(LSB)移至串行输出（serial_out），
// 最高有效位（MSB）通过串行输入（serial_in）置位。
reg [WIDTH-1:0] shadow;

assign 		serial_out = shadow[0];


// 需要对单比特情况进行特殊处理，因为单比特的移位操作不同
//
generate
  if (WIDTH == 1) begin: single_bit_gen
    always @(posedge clk or posedge rst)
      if (rst)
        shadow <= 1'b0;
      else if (select) begin
        if (shift)
          shadow <= serial_in;
        else if (capture)
          shadow <= capture_val;
      end
  end 
  else begin: multi_bit_gen
    always @(posedge clk or posedge rst)
      if (rst)
        shadow <= {WIDTH{1'b0}};
      else if (select) begin
        if (shift)
          shadow <= {serial_in, shadow[WIDTH-1:1]};
        else if (capture)
          shadow <= capture_val;
      end
  end
endgenerate

// 每当更新时钟上升时，输出寄存器异步复位，并从影子移位寄存器同步置位。
// 
// 基于参数值在q输出插入负边沿触发器或者不插入。
reg [WIDTH-1:0]   q_reg;

genvar 		  shdw_i;
generate
  for (shdw_i = 0; shdw_i < WIDTH; shdw_i = shdw_i + 1)
    begin: SHDW_LOOP
      
      if (SHDW_EN[shdw_i]) begin: shdw_flop_gen
        
        // 更新期间在下降沿更新Q
        always @(posedge clk_n or posedge rst)
          if (rst)
            q_reg[shdw_i] <= RST_VAL[shdw_i];
          else if (select & update)
            q_reg[shdw_i] <= shadow[shdw_i];

        assign q[shdw_i] = q_reg[shdw_i];

      end 
      else begin: shdw_dummy_gen

        // 插入一个伪触发器(稍后优化)来移除X和警告。
        always @(posedge clk_n or posedge rst)
          if (rst)
            q_reg[shdw_i] <= RST_VAL[shdw_i];
          else if (select & update)
            q_reg[shdw_i] <= RST_VAL[shdw_i];

          // 将shadow值直接传递到端点
          assign q[shdw_i] = shadow[shdw_i];
      end

    end // block: SHDW_LOOP
endgenerate
   
endmodule
